package cn.lexi.vip.util;

import com.google.common.base.Throwables;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import jodd.mail.Email;
import jodd.mail.SendMailSession;
import jodd.mail.SmtpServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PreDestroy;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 *
 * @author ycl from Yui
 * @since 2016-09-29
 */
@Singleton
public class EmailHelper {

    private final String useName;
    private final String password;
    private final String host;
    private static final Logger LOGGER = LoggerFactory.getLogger(EmailHelper.class);
    private static AtomicBoolean isRunning = new AtomicBoolean(true);
    private static BlockingQueue<Email> queue = new ArrayBlockingQueue(100);

    @Inject
    public EmailHelper(@Named("Email.userName") String useName,
                       @Named("Email.password") String password,
                       @Named("Email.smtpHostName") String host
    ) {
        this.useName = useName;
        this.password = password;
        this.host = host;
        initMailSession();
        new SendThread().start();
    }

    public String getUseName() {
        return useName;
    }

    public void sendEmail(Email email) {
        try {
            queue.put(email);
            LOGGER.info("Put email {}", Arrays.toString(email.getTo()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public SendMailSession initMailSession(
    ) {
        SmtpServer smtpServer = SmtpServer
                .create(this.host, 25)
                .property("mail.smtp.auth", "true")
                .authenticateWith(this.useName, this.password);
        SendMailSession session = smtpServer.createSession();
        session.open();
        return session;
    }

    private class SendThread extends Thread {
        @Override
        public void run() {
            while (isRunning.get()) {
                Email email = null;
                try {
                    if (email == null) {
                        email = queue.take();
                        LOGGER.debug("Get email :{}", email);
                        SendMailSession session = null;
                        try {
                            session = initMailSession();
                            String messageId = _retryingSendMail(session, email, 2, 1);
                            LOGGER.info("send email :{} success with messageId: {}", Arrays.toString(email.getTo()), messageId);
                            TimeUnit.SECONDS.sleep(2);
                        } finally {
                            if (session != null) {
                                session.close();
                            }
                        }
                    }
                } catch (Throwable e) {
                    if (email != null) {
                        if (e instanceof SocketTimeoutException) {
                            LOGGER.info("send email error email:{}:message:{} enqueue again", Arrays.toString(email.getTo()), e.getMessage());
                        } else {
                            LOGGER.error("send email error email:{}:message:{}", Arrays.toString(email.getTo()), e.getMessage());
                        }
                    }
                }
            }
        }
    }

    private String _retryingSendMail(SendMailSession session, Email email, int numTries, int tryNum) {
        if (tryNum > numTries) {
            LOGGER.error("send email {},after trying :{} times, error,forget it", Arrays.toString(email.getTo()), tryNum);
            return null;
        }
        try {
            return session.sendMail(email);
        } catch (IllegalStateException e) {
            LOGGER.info("send email {},after trying :{} times,error:{} ", Arrays.toString(email.getTo()), tryNum, Throwables.getStackTraceAsString(e));
            session = reConnect();
            return _retryingSendMail(session, email, numTries, tryNum + 1);
        } catch (Exception e) {
            LOGGER.error("send mail :{} , error:{}", Arrays.toString(email.getTo()), e.getMessage());
            return null;
        }
    }

    private SendMailSession reConnect() {
        SendMailSession session = initMailSession();
        LOGGER.info("reconnect smtp server....done");
        return session;
    }

    @PreDestroy
    public void close() {
        isRunning.set(false);
    }

//    public static void main(String[] args) throws InterruptedException {
//        EmailHelper helper = new EmailHelper("chunlian.yang@quantgroup.cn", "Lian0826", "smtp.exmail.qq.com");
//        Email email = Email.create().from(helper.getUseName()).to("chunlian.yang@quantgroup.cn").subject("abc").addText("xxxxxxxxxxxxxxxxxxxx");
//        helper.sendEmail(email);
//        helper.close();
//    }
}
